<?php
/**
 * Class for ATOM feeds generation
 * 
 * @author Sergei Stolyarov <sergei@regolit.com> 
 *
 */
class AtomGenerator
{
    /**
     * DOMDocument instance that represents atom feed document
     *
     * @var DOMDocument
     */
    private $doc;
    
    /**
     * DOMElement instance that represents feed itself
     *
     * @var DOMElement
     */
    private $feed;
    
    
    const ATOM_NS = 'http://www.w3.org/2005/Atom';
    
    /**
     * Initialize generator
     *
     * @param string $id 
     * @param string $title
     * @param DateTime $updated
     * @param string $author 
     */
    public function __construct($id, $site_url, $feed_url, $title, DateTime $updated, $author)
    {
        $this->doc = new DOMDocument('1.0', 'UTF-8');
        $this->feed = $this->newAtomElement('feed');
        $this->doc->appendChild($this->feed);
        $this->feed->appendChild($this->newAtomElement('id', $id));
        $this->feed->appendChild($this->newAtomElement('title', $title));
        
        $this->feed->appendChild($this->newAtomElement('updated', $updated->format('c')));
        
        $link_rel = $this->newAtomElement('link');
        $link_rel->setAttribute('href', $site_url);
        $link_rel->setAttribute('rel', 'alternate');
        $link_rel->setAttribute('type', 'text/html');
        $this->feed->appendChild($link_rel);
        $link_rel = $this->newAtomElement('link');
        $link_rel->setAttribute('href', $feed_url);
        $link_rel->setAttribute('rel', 'self');
        $link_rel->setAttribute('type', 'application/atom+xml');
        $this->feed->appendChild($link_rel);
        
        $this->feed->appendChild($this->newAtomElement('author', 
            $this->newAtomElement('name', $author)));
        $generator_node = $this->newAtomElement('generator', 'WereWord::AtomGenerator');
        $generator_node->setAttribute('uri', 'http://code.google.com/p/wereword/');
        $this->feed->appendChild($generator_node);
    }
    
    /**
     * Add feed entry
     *
     * @param string $id
     * @param string $title
     * @param DateTime $updated
     * @param DateTime $publised
     * @param string $content
     */
    public function appendEntry($id, $href, $title, DateTime $updated, DateTime $publised, $content, $categories)
    {
        $entry = $this->newAtomElement('entry');
        $entry->appendChild($this->newAtomElement('id', $id));
        
        $title_node = $this->newAtomElement('title', self::escapeXml($title));
        $title_node->setAttribute('type', 'html');
        $entry->appendChild($title_node);
        $entry->appendChild($this->newAtomElement('updated', $updated->format('c')));
        $entry->appendChild($this->newAtomElement('published', $publised->format('c')));
        
        foreach ($categories as $category) {
            $c = $this->newAtomElement('category');
            $c->setAttribute('term', $category);
            $entry->appendChild($c);
        }
        
        // semantics of <link rel="self"> is not clear for <entry> elements
        //$link_node = $this->newAtomElement('link');
        //$link_node->setAttribute('href', $href);
        //$link_node->setAttribute('rel', 'self');
        //$entry->appendChild($link_node);
        $link_node = $this->newAtomElement('link');
        $link_node->setAttribute('href', $href);
        $link_node->setAttribute('rel', 'alternate');
        $entry->appendChild($link_node);
        
        $content_node = $this->newAtomElement('content', self::escapeXml($content));
        $content_node->setAttribute('type', 'html');
        $entry->appendChild($content_node);
        
        $this->feed->appendChild($entry);
    }
    
    /**
     * Form and return resulting XML data
     * 
     * @return string
     *
     */
    public function dump()
    {
        return $this->doc->saveXML();
    }
    
    /**
     * Creates new DOMElement instance in the ATOM namespace
     *
     * @param string $name
     * @param mixed $value null, string or DOMElement value
     * @return DOMElement
     */
    protected function newAtomElement($name, $value=null)
    {
        $element = $this->doc->createElementNS(self::ATOM_NS, $name);
        if ($value instanceof DOMElement) {
            $element = $this->doc->createElementNS(self::ATOM_NS, $name);
            $element->appendChild($value);
        } else {
            $element = $this->doc->createElementNS(self::ATOM_NS, $name, $value);
        }
        return $element;
    }
    
    protected static function escapeXml($text)
    {
        return str_replace(array('&', '<'), array('&amp;', '&lt;'), $text);
    }
}
?>